/*
 *	Default item manager - module definition
 * 	Responsible for building and basic managing of default item
 */

jt.module('DefaultItem', function(context) {

	// useful shorthands
	var canvas = context.canvas,
		settings = context.settings,
		gh = context.settings.grid.h,
		gv = context.settings.grid.v,
		has = 'hasOwnProperty',
		fn = context.fn,
		container = context.container,
		viewport = context.viewport,

		items = {},

		itemAttributes = ['x', 'y', 'title', 'icon', 'w', 'h'],

		grid = (function() {

			var arr = function() {
					var grid = [];

					this.setValue = function(x, y, val) {
						if (!grid[y]) grid[y] = [];

						if (!grid[y][x]) grid[y][x] = [];

						grid[y][x].push(val);
					};

					this.removeValue = function(x, y, val) {
						if (!grid[y] || !grid[y][x]) return null;

						grid[y][x].splice(grid[y][x].indexOf(val), 1);
					}

					this.getValue = function(x, y) {
						if (!grid[y] || !grid[y][x]) return null;

						// get top most value
						return grid[y][x][grid[y][x].length - 1] || null;
					};
				};

			arr.prototype = {

				addItem: function addItemToGrid(item, posX, posY) {
					var gridPos = gridFromPos(posX, posY);
					this.setValue(gridPos.x, gridPos.y, item.id);
				},

				removeItem: function(item) {
					this.removeValue(item.x, item.y, item.id);
				}
			}

			return new arr();

		})(),

		cursor = {
			x: 0,
			y: 0,
			gridH: gh,
			gridV: gv
		},

		dragScale = 1.0,
		dragMode = settings.edit,

		options = util.extend({
			mouseOverSpeed: 150,
			mouseOutSpeed: 150,
			mouseOverScale: 1,
			mouseOutScale: 1,
			mouseOverRotation: 10,
			mouseOutRotation: 0,
			mouseOverEase: '>',
			mouseOutEase: '>',
			titleFontFamily: '"Lucida Grande","Lucida Sans Unicode",Helvetica, Arial, Verdana',
			titleFontSize: 11
		}, settings.DefaultItem || {}),

		selectedItem = null,
		hoveredItem = null;

	// Helper math functions


	function posFromGrid(posX, posY, width, height) {
		return {
			x: (posX * gh) + Math.abs(gh - (width || 0)) / 2,
			y: (posY * gv) + Math.abs(gv - (height || 0)) / 2 - 8
		}
	}

	function gridFromPos(posX, posY) {
		return {
			x: posX / gh,
			y: posY / gv,
		}
	}

	function addItemToGrid(item, posX, posY) {
		grid.addItem(item, posX, posY);
	}

	function removeItemFromGrid(item) {
		grid.removeItem(item);
	}

	function getItemFromPos(posX, posY) {
		var gridPos = gridFromPos(posX, posY);
		var itemId = grid.getValue(gridPos.x, gridPos.y);

		return items[itemId] || null;
	}

	function getItemFromGridPos(gridPosX, gridPosY) {
		var itemId = grid.getValue(gridPosX, gridPosY);

		return items[itemId] || null;
	}

	function isRectInDesktopBound(x, y, width, height) {
		return (x >= 0 && x + width <= container.offsetWidth) && (y >= 0 && y + height <= container.offsetHeight)
	}

	function setDragMode(enabled) {
		context.event('dragMode', enabled);
	}

	// Drag event handlers
	var onDragStart = function(x, y) {

			if (!dragMode) return;

			cursor.x = Raphael.snapTo(gh, x, gh);
			cursor.y = Raphael.snapTo(gv, y, gv);
			context.event('itemCursorUpdate', cursor.x, cursor.y);

			var handle = this.handle;
			handle.dragEvent = {
				started: true,
				active: false,
				x: x,
				y: y
			};
		},

		onDragMove = function(dx, dy) {

			var handle = this.handle,
				elements = this.elements,
				dragEvent = this.handle.dragEvent;

			if (dragEvent.started && (Math.abs(dx) + Math.abs(dy) > 5)) {

				this.draggable = true;
				dragEvent.active = true;
				dragEvent.started = false;

				handle.ox = handle.attr('x');
				handle.oy = handle.attr('y');
				handle.scale(dragScale);
				handle.attr({
					opacity: 0.8
				});
				elements.attr({
					opacity: 0.8
				});
				handle.toFront();
				this.titleShadow.toFront();
				this.title.toFront();

				removeItemFromGrid(this.ref);
				
				//this.elements.animate({opacity: 0}, 400, '>');
				context.event('itemDragStart', this, gridFromPos(cursor.x, cursor.y));
			}

			if (!dragMode || !this.draggable) return;


			handle.node.style.cursor = 'move';
			context.container.style.cursor = 'move';

			var bbox = handle.getBBox();

			if (isRectInDesktopBound(Raphael.snapTo(gh, bbox.x, gh), Raphael.snapTo(gv, bbox.y, gv), gv, gh)) {

				cursor.x = Raphael.snapTo(gh, bbox.x, gh);
				cursor.y = Raphael.snapTo(gv, bbox.y, gv);
				context.event('itemCursorUpdate', cursor.x, cursor.y);
			}

			var pos = {
				x: dx + handle.ox,
				y: dy + handle.oy
			};
			handle.attr(pos);
			this.elements.attr({
				x: dx + handle.ox,
				y: dy + handle.oy
			});

			context.event('itemDragMove', this, pos);
		},

		onDragEnd = function() {

			if (!dragMode || !this.draggable) return;

			var handle = this.handle;
			
			handle.node.style.cursor = 'default';
			context.container.style.cursor = 'default';

			var bbox = handle.getBBox(),
				offsetX = handle.attr('width') < gh ? Math.abs(gh - handle.attr('width')) / 2 : gh / 2,
				offsetY = handle.attr('height') < gv ? Math.abs(gv - handle.attr('height')) / 2 - 8 : gv / 2;

			handle.scale('1');
			handle.attr({
				x: bbox.x,
				y: bbox.y,
				rotation: 0
			});
			handle.animate({
				x: cursor.x + offsetX,
				y: cursor.y + offsetY,
				opacity: 1
			}, 500, 'elastic');
			this.elements.animate({
				x: cursor.x + offsetX,
				y: cursor.y + offsetY
			}, 500, 'elastic');

			// get item from drag end position and if any exist fire event
			var oldItem = getItemFromPos(cursor.x, cursor.y);

			this.elements.show();
			this.elements.attr({
				'opacity': '1'
			});

			addItemToGrid(this.ref, cursor.x, cursor.y);
			util.extend(this.ref, gridFromPos(cursor.x, cursor.y));

			if (oldItem && oldItem != this) {

				context.event('itemDragCollision', this, oldItem, gridFromPos(cursor.x, cursor.y));
			} else {

				// if item exist here it means we have old ref to this item and we need to remove it.
				if (oldItem) {
					removeItemFromGrid(this.ref);
				}

				context.event('itemDragEnd', this, gridFromPos(cursor.x, cursor.y));
			}

			handle.dragEvent.started = false;
			this.draggable = false;
		};

	// Event handlers
	var events = {

		/*
		 *	Summary: Initialize module event handler
		 */
		init: function() {
			context.log('[DefaultItemManager] init');

			/* 	 
			 * Desktop fn
			 */

			fn.extend({
				dragMode: setDragMode,
				dragItem: this.dragItem,
				undragItem: this.undragItem,
				dragAll: this.dragAll,
				undragAll: this.undragAll
			});

			// expose item grid
			context.event('itemGridReady', grid);
		},

		/*
		 *	Summary: addItem event handler. Responsible for building default item.
		 *	Arguments: item object from desktop and itemSettings parameters.
		 */
		addItem: function(item, itemSettings) {

			if (item.classes.indexOf('default') > -1 && !items[item.id]) {

				// Item settings
				var it = {};
				it.ref = item,

				settings = util.extend({
					icon: '',
					w: 36,
					h: 36,
					title: '',
					x: 0,
					y: 0,
					titleFontFamily: '',
					titleFontSize: '',
				}, itemSettings);

				util.extend(it.ref, settings);

				var itemPos = posFromGrid(settings.x, settings.y, settings.w, settings.h);

				it.handle = canvas.image(settings.icon, itemPos.x, itemPos.y, settings.w, settings.h);
				grid.setValue(settings.x, settings.y, item.id);

				it.title = canvas.text(itemPos.x, itemPos.y, settings.title).attr({
					'font-family': settings.titleFontFamily || options.titleFontFamily,
					'font-weight': 'normal',
					'font-style': 'normal',
					'font-size': settings.titleFontSize || options.titleFontSize, 
					'fill': '#FFF',
					'text-anchor': 'start'
				});

				it.titleShadow = canvas.text(itemPos.x, itemPos.y, settings.title).attr({
					'font-family': settings.titleFontFamily || options.titleFontFamily,
					'font-weight': 'normal',
					'font-style': 'normal',
					'font-size': settings.titleFontSize || options.titleFontSize, 
					'fill': '#000',
					'stroke': '#000',
					'stroke-width': '2.6',
					'stroke-opacity': '0.5',
					'text-anchor': 'start'
				}).toBack();

				var itemCenterX = (settings.w - it.title.getBBox().width) / 2;

				it.title.translate(itemCenterX, settings.h + 8);
				it.titleShadow.translate(itemCenterX + 1, settings.h + 9);

				it.titleBackground = canvas.set();

				it.elements = canvas.set();
				it.elements.push(it.title, it.titleShadow, it.titleBackground);


				//it.title.node.setAttribute("x",0);
				//it.title.node.setAttribute("y", 0);
				// this.titleShadow.node.setAttribute("x", dx + handle.ox);
				// this.titleShadow.node.setAttribute("y", dy + handle.oy);
				// Initialize drag events
				it.canDrag = true;
				it.draggable = false;
				it.handle.drag(onDragMove, onDragStart, onDragEnd, it, it, it);

				it.handle.dragEvent = {
					started: false,
					active: false,
					x: 0,
					y: 0
				}
				// add eventss
				it.handle.mousedown(function(event) {});

				it.handle.mousemove(function(event) {});

				it.handle.mouseover(function(event) {

					this.node.style.cursor = 'pointer';

					if (dragMode && it.draggable) return;

					hoveredItem = it;
					if (selectedItem !== it) {
						// some animation on mouse over item
						this.animate({
							rotation: options.mouseOverRotation,
							scale: options.mouseOverScale
						}, options.mouseOverSpeed, options.mouseOverEase);
					}
					it.hovered = true;
					context.event('itemMouseOver', it);
				});

				it.handle.mouseout(function(event) {

					this.node.style.cursor = 'arrow';

					if (dragMode && it.draggable) return;

					hoveredItem = null;
					//if(selectedItem !== it) {
					// back to original visual state after mouse out of item
					this.animate({
						rotation: options.mouseOutRotation,
						scale: options.mouseOutScale
					}, options.mouseOutSpeed, options.mouseOutEase);
					//}
					it.hovered = false;
					context.event('itemMouseOut', it);
				});

				it.handle.click(function(event) {

					if ((dragMode && it.draggable) || it.handle.dragEvent.active) return;

					if (selectedItem) {
						selectedItem.selected = false;
						context.event('itemUnselected', selectedItem);
					}

					it.selected = true;
					context.event('itemSelected', it);

					selectedItem = it;
					util.stopPropagation(event);
				});

				it.handle.dblclick(function(event) {
					if (dragMode && it.draggable) return;

					context.event('itemDblClick', it);
				});

				// Item ready
				items[item.id] = it;
				context.event('addDefaultItem', it, settings);
			}
		},

		mouseClick: function() {

			if (!selectedItem || selectedItem === hoveredItem) return;

			selectedItem.elements.stop();
			selectedItem.elements.show();
			selectedItem.handle.animate({
				scale: '1'
			}, 200, '>');
			selectedItem.elements.attr({
				opacity: '1'
			});
			selectedItem.titleBackground.attr({
				'opacity': '0.5'
			}, 200, '>');

			selectedItem.selected = false;
			context.event('itemUnselected', selectedItem);

			selectedItem = null;
		},

		itemAttrChange: function(itemId, attr, value) {
			var item = items[itemId];

			if (!item || itemAttributes.indexOf(attr) === -1) {
				return;
			}

			if (attr === 'x') {

				grid.removeValue(item.ref.x, item.ref.y, item.ref.id);
				item.ref[attr] = value;
				grid.setValue(item.ref.x, item.ref.y, item.ref.id);

				var itemPos = posFromGrid(item.ref.x, item.ref.y, item.ref.w, item.ref.h);

				item.handle.stop().attr({
					'x': itemPos.x
				});
				item.elements.stop().attr({
					'x': itemPos.x
				})

			} else if (attr === 'y') {

				grid.removeValue(item.ref.x, item.ref.y, item.ref.id);
				item.ref[attr] = value;
				grid.setValue(item.ref.x, item.ref.y, item.ref.id);

				var itemPos = posFromGrid(item.ref.x, item.ref.y, item.ref.w, item.ref.h);

				item.handle.stop().attr({
					'y': itemPos.y
				});
				item.elements.stop().attr({
					'y': itemPos.y
				});

			} else if (attr === 'title') {
				item.title.attr({
					'text': value
				});
				item.titleShadow.attr({
					'text': value
				});
			} else if (attr === 'w') {
				item.handle.stop().attr({
					'width': value
				});
			} else if (attr === 'h') {
				item.handle.stop().attr({
					'height': value
				});
			} else if (attr === 'icon') {
				item.handle.stop().attr({
					'src': value
				});
			}

			item.ref[attr] = value;

			var itemPos = posFromGrid(item.ref.y, item.ref.y, item.ref.w, item.ref.h),
				itemCenterX = (item.ref.w - item.title.getBBox().width) / 2;

			item.title.attr({
				transform: ['T', itemCenterX, item.ref.h + item.title.getBBox().height / 2 + 2]
			});
			item.titleShadow.attr({
				transform: ['T', itemCenterX + 1, item.ref.h + item.title.getBBox().height / 2 + 3]
			});
			item.titleBackground.attr({
				transform: ['T', itemCenterX - 10, item.ref.h + 5],
				width: item.ref.title ? item.title.getBBox().width + 20 : 0,
				height: item.ref.title ? item.title.getBBox().height + 3 : 0
			});

		},

		attrChange: function(name, value) {
			switch (name) {
			case 'edit':
				dragMode = value;
				break
			case 'item':
				util.extend(options, value);
				break;
			}
		},

		removeItem: function(itemId) {
			var item = items[itemId];

			if (!item) {
				return;
			}

			context.event('removeDefaultItem', item);

			item.handle.remove();
			item.elements.remove();
			items[itemId] = null;

			if (selectedItem === item) {
				selectedItem = null;
			}

			item = null;
		},

		showItem: function(itemId) {
			var item = items[itemId];

			if (!item) {
				return;
			}

			item.handle.show();
			item.elements.show();
		},

		hideItem: function(itemId) {
			var item = items[itemId];

			if (!item) {
				return;
			}

			item.handle.hide();
			item.elements.hide();
		},

		dragItem: function(itemId) {
			var item = items[itemId];

			if (item) {
				item.canDrag = true;
			}
		},

		undragItem: function(itemId) {
			var item = items[itemId];

			if (item) {
				item.canDrag = false;
			}
		},

		dragAll: function() {
			for (var item in items) {
				if (items.hasOwnProperty(item)) {
					items[item].canDrag = true;
				}
			}
		},

		undragAll: function() {
			for (var item in items) {
				if (items.hasOwnProperty(item)) {
					items[item].canDrag = false;
				}
			}
		},

		dragMode: function(enabled) {
			dragMode = enabled || false;
		}
	}

	// Expose module definition for more late creation.
	return {
		events: events
	}

});